home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / ImageMagick / magick / shear.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  37.9 KB  |  1,288 lines

  1. /*
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. %                                                                             %
  4. %                                                                             %
  5. %                                                                             %
  6. %                      SSSSS  H   H  EEEEE   AAA    RRRR                      %
  7. %                      SS     H   H  E      A   A   R   R                     %
  8. %                       SSS   HHHHH  EEE    AAAAA   RRRR                      %
  9. %                         SS  H   H  E      A   A   R R                       %
  10. %                      SSSSS  H   H  EEEEE  A   A   R  R                      %
  11. %                                                                             %
  12. %                                                                             %
  13. %              Shear or rotate a raster image by an arbitrary angle.          %
  14. %                                                                             %
  15. %                                                                             %
  16. %                                                                             %
  17. %                               Software Design                               %
  18. %                                 John Cristy                                 %
  19. %                                  July 1992                                  %
  20. %                                                                             %
  21. %                                                                             %
  22. %  Copyright 1994 E. I. du Pont de Nemours & Company                          %
  23. %                                                                             %
  24. %  Permission to use, copy, modify, distribute, and sell this software and    %
  25. %  its documentation for any purpose is hereby granted without fee,           %
  26. %  provided that the above Copyright notice appear in all copies and that     %
  27. %  both that Copyright notice and this permission notice appear in            %
  28. %  supporting documentation, and that the name of E. I. du Pont de Nemours    %
  29. %  & Company not be used in advertising or publicity pertaining to            %
  30. %  distribution of the software without specific, written prior               %
  31. %  permission.  E. I. du Pont de Nemours & Company makes no representations   %
  32. %  about the suitability of this software for any purpose.  It is provided    %
  33. %  "as is" without express or implied warranty.                               %
  34. %                                                                             %
  35. %  E. I. du Pont de Nemours & Company disclaims all warranties with regard    %
  36. %  to this software, including all implied warranties of merchantability      %
  37. %  and fitness, in no event shall E. I. du Pont de Nemours & Company be       %
  38. %  liable for any special, indirect or consequential damages or any           %
  39. %  damages whatsoever resulting from loss of use, data or profits, whether    %
  40. %  in an action of contract, negligence or other tortuous action, arising     %
  41. %  out of or in connection with the use or performance of this software.      %
  42. %                                                                             %
  43. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  44. %
  45. %  Function RotateImage, XShearImage, and YShearImage is based on the paper
  46. %  "A Fast Algorithm for General Raster Rotatation" by Alan W. Paeth,
  47. %  Graphics Interface '86 (Vancouver).  RotateImage is adapted from a similiar
  48. %  routine based on the Paeth paper written by Michael Halle of the Spatial
  49. %  Imaging Group, MIT Media Lab.
  50. %
  51. %
  52. */
  53.  
  54. /*
  55.   Include declarations.
  56. */
  57. #include "magick.h"
  58. #include "image.h"
  59.  
  60. /*
  61. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  62. %                                                                             %
  63. %                                                                             %
  64. %                                                                             %
  65. %   C l i p S h e a r I m a g e                                               %
  66. %                                                                             %
  67. %                                                                             %
  68. %                                                                             %
  69. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  70. %
  71. %  Function ClipShearImage clips the sheared image as determined by the
  72. %  bounding box as defined by width and height and shearing angles.
  73. %
  74. %  The format of the ClipShearImage routine is:
  75. %
  76. %      ClipShearImage(image,x_shear,y_shear,width,height,clip)
  77. %
  78. %  A description of each parameter follows.
  79. %
  80. %    o image: The address of a structure of type Image.
  81. %
  82. %    o x_shear, y_shear, width, height: Defines a region of the image to clip.
  83. %
  84. %    o clip: A value other than zero clips the corners of the rotated
  85. %      image and retains the original image size.
  86. %
  87. %
  88. */
  89. static Image *ClipShearImage(image,x_shear,y_shear,width,height,clip)
  90. Image
  91.   *image;
  92.  
  93. double
  94.   x_shear,
  95.   y_shear;
  96.  
  97. unsigned int
  98.   width,
  99.   height,
  100.   clip;
  101. {
  102.   typedef struct Point
  103.   {
  104.     double
  105.       x,
  106.       y;
  107.   } Point;
  108.  
  109.   double
  110.     x_max,
  111.     x_min,
  112.     y_max,
  113.     y_min;
  114.  
  115.   Image
  116.     *clipped_image;
  117.  
  118.   Point
  119.     corners[4];
  120.  
  121.   RectangleInfo
  122.     clip_info;
  123.  
  124.   register int
  125.     i;
  126.  
  127.   /*
  128.     Calculate the rotated image size.
  129.   */
  130.   clip_info.width=width;
  131.   clip_info.height=height;
  132.   corners[0].x=(-((int) clip_info.width)/2.0);
  133.   corners[0].y=(-((int) clip_info.height)/2.0);
  134.   corners[1].x=((int) clip_info.width)/2.0;
  135.   corners[1].y=(-((int) clip_info.height)/2.0);
  136.   corners[2].x=(-((int) clip_info.width)/2.0);
  137.   corners[2].y=((int) clip_info.height)/2.0;
  138.   corners[3].x=((int) clip_info.width)/2.0;
  139.   corners[3].y=((int) clip_info.height)/2.0;
  140.   for (i=0; i < 4; i++)
  141.   {
  142.     corners[i].x+=x_shear*corners[i].y;
  143.     corners[i].y+=y_shear*corners[i].x;
  144.     corners[i].x+=x_shear*corners[i].y;
  145.     corners[i].x+=(image->columns-1)/2.0;
  146.     corners[i].y+=(image->rows-3)/2.0;
  147.   }
  148.   x_min=corners[0].x;
  149.   y_min=corners[0].y;
  150.   x_max=corners[0].x;
  151.   y_max=corners[0].y;
  152.   for (i=1; i < 4; i++)
  153.   {
  154.     if (x_min > corners[i].x)
  155.       x_min=corners[i].x;
  156.     if (y_min > corners[i].y)
  157.       y_min=corners[i].y;
  158.     if (x_max < corners[i].x)
  159.       x_max=corners[i].x;
  160.     if (y_max < corners[i].y)
  161.       y_max=corners[i].y;
  162.   }
  163.   x_min=floor((double) x_min);
  164.   x_max=ceil((double) x_max);
  165.   y_min=floor((double) y_min);
  166.   y_max=ceil((double) y_max);
  167.   if (!clip)
  168.     {
  169.       /*
  170.         Do not clip sheared image.
  171.       */
  172.       clip_info.width=(unsigned int) (x_max-x_min);
  173.       clip_info.height=(unsigned int) (y_max-y_min);
  174.     }
  175.   clip_info.x=(int) x_min+(((int) (x_max-x_min)-clip_info.width) >> 1);
  176.   clip_info.y=(int) y_min+(((int) (y_max-y_min)-clip_info.height) >> 1);
  177.   /*
  178.     Clip image and return.
  179.   */
  180.   clipped_image=ClipImage(image,&clip_info);
  181.   return(clipped_image);
  182. }
  183.  
  184. /*
  185. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  186. %                                                                             %
  187. %                                                                             %
  188. %                                                                             %
  189. %   I n t e g r a l R o t a t e I m a g e                                     %
  190. %                                                                             %
  191. %                                                                             %
  192. %                                                                             %
  193. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  194. %
  195. %  Function IntegralRotateImage rotates the image an integral of 90 degrees.
  196. %  It allocates the memory necessary for the new Image structure and returns
  197. %  a pointer to the rotated image.
  198. %
  199. %  The format of the IntegralRotateImage routine is:
  200. %
  201. %      rotated_image=IntegralRotateImage(image,rotations)
  202. %
  203. %  A description of each parameter follows.
  204. %
  205. %    o rotated_image: Function IntegralRotateImage returns a pointer to the
  206. %      rotated image.  A null image is returned if there is a a memory shortage.
  207. %
  208. %    o image: The address of a structure of type Image.
  209. %
  210. %    o rotations: Specifies the number of 90 degree rotations.
  211. %
  212. %
  213. */
  214. static Image *IntegralRotateImage(image,rotations)
  215. Image
  216.   *image;
  217.  
  218. unsigned int
  219.   rotations;
  220. {
  221.   Image
  222.     *rotated_image;
  223.  
  224.   register RunlengthPacket
  225.     *p,
  226.     *q;
  227.  
  228.   register int
  229.     x,
  230.     y;
  231.  
  232.   /*
  233.     Initialize rotated image attributes.
  234.   */
  235.   rotations%=4;
  236.   if ((rotations == 1) || (rotations == 3))
  237.     rotated_image=CopyImage(image,image->rows,image->columns,False);
  238.   else
  239.     rotated_image=CopyImage(image,image->columns,image->rows,False);
  240.   if (rotated_image == (Image *) NULL)
  241.     {
  242.       Warning("Unable to rotate image","Memory allocation failed");
  243.       return((Image *) NULL);
  244.     }
  245.   /*
  246.     Expand runlength packets into a rectangular array of pixels.
  247.   */
  248.   p=image->pixels;
  249.   image->runlength=p->length+1;
  250.   switch (rotations)
  251.   {
  252.     case 0:
  253.     {
  254.       /*
  255.         Rotate 0 degrees.
  256.       */
  257.       q=rotated_image->pixels;
  258.       for (y=0; y < image->rows; y++)
  259.       {
  260.         for (x=0; x < image->columns; x++)
  261.         {
  262.           if (image->runlength != 0)
  263.             image->runlength--;
  264.           else
  265.             {
  266.               p++;
  267.               image->runlength=p->length;
  268.             }
  269.           *q=(*p);
  270.           q->length=0;
  271.           q++;
  272.         }
  273.       }
  274.       break;
  275.     }
  276.     case 1:
  277.     {
  278.       /*
  279.         Rotate 90 degrees.
  280.       */
  281.       for (x=0; x < rotated_image->columns; x++)
  282.       {
  283.         q=rotated_image->pixels+(rotated_image->columns-x)-1;
  284.         for (y=0; y < rotated_image->rows; y++)
  285.         {
  286.           if (image->runlength != 0)
  287.             image->runlength--;
  288.           else
  289.             {
  290.               p++;
  291.               image->runlength=p->length;
  292.             }
  293.           *q=(*p);
  294.           q->length=0;
  295.           q+=rotated_image->columns;
  296.         }
  297.       }
  298.       break;
  299.     }
  300.     case 2:
  301.     {
  302.       /*
  303.         Rotate 180 degrees.
  304.       */
  305.       q=rotated_image->pixels+(rotated_image->columns*rotated_image->rows)-1;
  306.       for (y=image->rows-1; y >= 0; y--)
  307.       {
  308.         for (x=0; x < image->columns; x++)
  309.         {
  310.           if (image->runlength != 0)
  311.             image->runlength--;
  312.           else
  313.             {
  314.               p++;
  315.               image->runlength=p->length;
  316.             }
  317.           *q=(*p);
  318.           q->length=0;
  319.           q--;
  320.         }
  321.       }
  322.       break;
  323.     }
  324.     case 3:
  325.     {
  326.       /*
  327.         Rotate 270 degrees.
  328.       */
  329.       for (x=rotated_image->columns-1; x >= 0; x--)
  330.       {
  331.         q=rotated_image->pixels+(rotated_image->columns*rotated_image->rows)-
  332.           x-1;
  333.         for (y=0; y < rotated_image->rows; y++)
  334.         {
  335.           if (image->runlength != 0)
  336.             image->runlength--;
  337.           else
  338.             {
  339.               p++;
  340.               image->runlength=p->length;
  341.             }
  342.           *q=(*p);
  343.           q->length=0;
  344.           q-=rotated_image->columns;
  345.         }
  346.       }
  347.       break;
  348.     }
  349.   }
  350.   return(rotated_image);
  351. }
  352.  
  353. /*
  354. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  355. %                                                                             %
  356. %                                                                             %
  357. %                                                                             %
  358. %   X S h e a r I m a g e                                                     %
  359. %                                                                             %
  360. %                                                                             %
  361. %                                                                             %
  362. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  363. %
  364. %  Procedure XShearImage shears the image in the X direction with a shear angle
  365. %  of 'degrees'.  Positive angles shear counter-clockwise (right-hand rule),
  366. %  and negative angles shear clockwise.  Angles are measured relative to a
  367. %  vertical Y-axis.  X shears will widen an image creating 'empty' triangles
  368. %  on the left and right sides of the source image.
  369. %
  370. %  The format of the XShearImage routine is:
  371. %
  372. %      XShearImage(image,degrees,width,height,x_offset,y_offset,background,
  373. %        range_limit)
  374. %
  375. %  A description of each parameter follows.
  376. %
  377. %    o image: The address of a structure of type Image.
  378. %
  379. %    o degrees: A double representing the shearing angle along the X axis.
  380. %
  381. %    o width, height, x_offset, y_offset: Defines a region of the image
  382. %      to shear.
  383. %
  384. %    o background: Specifies a ColorPacket used to fill empty triangles
  385. %      left over from shearing.
  386. %
  387. %
  388. */
  389. static void XShearImage(image,degrees,width,height,x_offset,y_offset,background,
  390.   range_limit)
  391. Image
  392.   *image;
  393.  
  394. double
  395.   degrees;
  396.  
  397. unsigned int
  398.   width,
  399.   height;
  400.  
  401. int
  402.   x_offset,
  403.   y_offset;
  404.  
  405. ColorPacket
  406.   background;
  407.  
  408. register unsigned char
  409.   *range_limit;
  410. {
  411.   double
  412.     displacement;
  413.  
  414.   enum {LEFT,RIGHT}
  415.     direction;
  416.  
  417.   int
  418.     step,
  419.     y;
  420.  
  421.   long
  422.     fractional_step;
  423.  
  424.   register RunlengthPacket
  425.     *p,
  426.     *q;
  427.  
  428.   register int
  429.     blue,
  430.     green,
  431.     i,
  432.     index,
  433.     red;
  434.  
  435.   RunlengthPacket
  436.     last_pixel;
  437.  
  438.   y_offset--;
  439.   for (y=0; y < height; y++)
  440.   {
  441.     y_offset++;
  442.     displacement=degrees*(((double) y)-(height-1)/2.0);
  443.     if (displacement == 0.0)
  444.       continue;
  445.     if (displacement > 0.0)
  446.       direction=RIGHT;
  447.     else
  448.       {
  449.         displacement*=(-1.0);
  450.         direction=LEFT;
  451.       }
  452.     step=(int) floor(displacement);
  453.     fractional_step=UpShifted(displacement-(double) step);
  454.     if (fractional_step == 0)
  455.       {
  456.         /*
  457.           No fractional displacement-- just copy.
  458.         */
  459.         switch (direction)
  460.         {
  461.           case LEFT:
  462.           {
  463.             /*
  464.               Transfer pixels left-to-right.
  465.             */
  466.             p=image->pixels+image->columns*y_offset+x_offset;
  467.             q=p-step;
  468.             for (i=0; i < width; i++)
  469.             {
  470.               *q=(*p);
  471.               q++;
  472.               p++;
  473.             }
  474.             /*
  475.               Set old row to background color.
  476.             */
  477.             for (i=0; i < step; i++)
  478.             {
  479.               q->red=background.red;
  480.               q->green=background.green;
  481.               q->blue=background.blue;
  482.               q->index=background.index;
  483.               q++;
  484.             }
  485.             break;
  486.           }
  487.           case RIGHT:
  488.           {
  489.             /*
  490.               Transfer pixels right-to-left.
  491.             */
  492.             p=image->pixels+image->columns*y_offset+x_offset+width;
  493.             q=p+step;
  494.             for (i=0; i < width; i++)
  495.             {
  496.               p--;
  497.               q--;
  498.               *q=(*p);
  499.             }
  500.             /*
  501.               Set old row to background color.
  502.             */
  503.             for (i=0; i < step; i++)
  504.             {
  505.               q--;
  506.               q->red=background.red;
  507.               q->green=background.green;
  508.               q->blue=background.blue;
  509.               q->index=background.index;
  510.             }
  511.             break;
  512.           }
  513.         }
  514.         continue;
  515.       }
  516.     /*
  517.       Fractional displacement.
  518.     */
  519.     step++;
  520.     last_pixel.red=background.red;
  521.     last_pixel.green=background.green;
  522.     last_pixel.blue=background.blue;
  523.     last_pixel.index=background.index;
  524.     switch (direction)
  525.     {
  526.       case LEFT:
  527.       {
  528.         /*
  529.           Transfer pixels left-to-right.
  530.         */
  531.         p=image->pixels+image->columns*y_offset+x_offset;
  532.         q=p-step;
  533.         for (i=0; i < width; i++)
  534.         {
  535.           red=DownShift(last_pixel.red*(UpShift(1)-fractional_step)+p->red*
  536.             fractional_step);
  537.           green=DownShift(last_pixel.green*(UpShift(1)-fractional_step)+
  538.             p->green*fractional_step);
  539.           blue=DownShift(last_pixel.blue*(UpShift(1)-fractional_step)+p->blue*
  540.             fractional_step);
  541.           index=DownShift(last_pixel.index*(UpShift(1)-fractional_step)+
  542.             p->index*fractional_step);
  543.           last_pixel=(*p);
  544.           p++;
  545.           q->red=range_limit[red];
  546.           q->green=range_limit[green];
  547.           q->blue=range_limit[blue];
  548.           if (index < 0)
  549.             q->index=0;
  550.           else
  551.             if (index > MaxColormapSize)
  552.               q->index=MaxColormapSize;
  553.             else
  554.               q->index=(unsigned short) index;
  555.           q++;
  556.         }
  557.         /*
  558.           Set old row to background color.
  559.         */
  560.         red=DownShift(last_pixel.red*(UpShift(1)-fractional_step)+
  561.           background.red*fractional_step);
  562.         green=DownShift(last_pixel.green*(UpShift(1)-fractional_step)+
  563.           background.green*fractional_step);
  564.         blue=DownShift(last_pixel.blue*(UpShift(1)-fractional_step)+
  565.           background.blue*fractional_step);
  566.         index=DownShift(last_pixel.index*(UpShift(1)-fractional_step)+
  567.           background.index*fractional_step);
  568.         q->red=range_limit[red];
  569.         q->green=range_limit[green];
  570.         q->blue=range_limit[blue];
  571.         if (index < 0)
  572.           q->index=0;
  573.         else
  574.           if (index > MaxColormapSize)
  575.             q->index=MaxColormapSize;
  576.           else
  577.             q->index=(unsigned short) index;
  578.         q++;
  579.         for (i=0; i < step-1; i++)
  580.         {
  581.           q->red=background.red;
  582.           q->green=background.green;
  583.           q->blue=background.blue;
  584.           q->index=background.index;
  585.           q++;
  586.         }
  587.         break;
  588.       }
  589.       case RIGHT:
  590.       {
  591.         /*
  592.           Transfer pixels right-to-left.
  593.         */
  594.         p=image->pixels+image->columns*y_offset+x_offset+width;
  595.         q=p+step;
  596.         for (i=0; i < width; i++)
  597.         {
  598.           p--;
  599.           red=DownShift(last_pixel.red*(UpShift(1)-fractional_step)+p->red*
  600.             fractional_step);
  601.           green=DownShift(last_pixel.green*(UpShift(1)-fractional_step)+
  602.             p->green*fractional_step);
  603.           blue=DownShift(last_pixel.blue*(UpShift(1)-fractional_step)+p->blue*
  604.             fractional_step);
  605.           index=DownShift(last_pixel.index*(UpShift(1)-fractional_step)+
  606.             p->index*fractional_step);
  607.           last_pixel=(*p);
  608.           q--;
  609.           q->red=range_limit[red];
  610.           q->green=range_limit[green];
  611.           q->blue=range_limit[blue];
  612.           if (index < 0)
  613.             q->index=0;
  614.           else
  615.             if (index > MaxColormapSize)
  616.               q->index=MaxColormapSize;
  617.             else
  618.               q->index=(unsigned short) index;
  619.         }
  620.         /*
  621.           Set old row to background color.
  622.         */
  623.         red=DownShift(last_pixel.red*(UpShift(1)-fractional_step)+
  624.           background.red*fractional_step);
  625.         green=DownShift(last_pixel.green*(UpShift(1)-fractional_step)+
  626.           background.green*fractional_step);
  627.         blue=DownShift(last_pixel.blue*(UpShift(1)-fractional_step)+
  628.           background.blue*fractional_step);
  629.         index=DownShift(last_pixel.index*(UpShift(1)-fractional_step)+
  630.           background.index*fractional_step);
  631.         q--;
  632.         q->red=range_limit[red];
  633.         q->green=range_limit[green];
  634.         q->blue=range_limit[blue];
  635.         if (index < 0)
  636.           q->index=0;
  637.         else
  638.           if (index > MaxColormapSize)
  639.             q->index=MaxColormapSize;
  640.           else
  641.             q->index=(unsigned short) index;
  642.         for (i=0; i < step-1; i++)
  643.         {
  644.           q--;
  645.           q->red=background.red;
  646.           q->green=background.green;
  647.           q->blue=background.blue;
  648.           q->index=background.index;
  649.         }
  650.         break;
  651.       }
  652.     }
  653.   }
  654. }
  655.  
  656. /*
  657. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  658. %                                                                             %
  659. %                                                                             %
  660. %                                                                             %
  661. %   Y S h e a r I m a g e                                                     %
  662. %                                                                             %
  663. %                                                                             %
  664. %                                                                             %
  665. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  666. %
  667. %  Procedure YShearImage shears the image in the Y direction with a shear
  668. %  angle of 'degrees'.  Positive angles shear counter-clockwise (right-hand
  669. %  rule), and negative angles shear clockwise.  Angles are measured relative
  670. %  to a horizontal X-axis.  Y shears will increase the height of an image
  671. %  creating 'empty' triangles on the top and bottom of the source image.
  672. %
  673. %  The format of the YShearImage routine is:
  674. %
  675. %      YShearImage(image,degrees,width,height,x_offset,y_offset,background,
  676. %        range_limit)
  677. %
  678. %  A description of each parameter follows.
  679. %
  680. %    o image: The address of a structure of type Image.
  681. %
  682. %    o degrees: A double representing the shearing angle along the Y axis.
  683. %
  684. %    o width, height, x_offset, y_offset: Defines a region of the image
  685. %      to shear.
  686. %
  687. %    o background: Specifies a ColorPacket used to fill empty triangles
  688. %      left over from shearing.
  689. %
  690. %
  691. */
  692. static void YShearImage(image,degrees,width,height,x_offset,y_offset,background,
  693.   range_limit)
  694. Image
  695.   *image;
  696.  
  697. double
  698.   degrees;
  699.  
  700. unsigned int
  701.   width,
  702.   height;
  703.  
  704. int
  705.   x_offset,
  706.   y_offset;
  707.  
  708. ColorPacket
  709.   background;
  710.  
  711. register unsigned char
  712.   *range_limit;
  713. {
  714.   double
  715.     displacement;
  716.  
  717.   enum {UP,DOWN}
  718.     direction;
  719.  
  720.   int
  721.     step,
  722.     y;
  723.  
  724.   long
  725.     fractional_step;
  726.  
  727.   register RunlengthPacket
  728.     *p,
  729.     *q;
  730.  
  731.   register int
  732.     blue,
  733.     green,
  734.     i,
  735.     index,
  736.     red;
  737.  
  738.   RunlengthPacket
  739.     last_pixel;
  740.  
  741.   x_offset--;
  742.   for (y=0; y < width; y++)
  743.   {
  744.     x_offset++;
  745.     displacement=degrees*(((double) y)-(width-1)/2.0);
  746.     if (displacement == 0.0)
  747.       continue;
  748.     if (displacement > 0.0)
  749.       direction=DOWN;
  750.     else
  751.       {
  752.         displacement*=(-1.0);
  753.         direction=UP;
  754.       }
  755.     step=(int) floor(displacement);
  756.     fractional_step=UpShifted(displacement-(double) step);
  757.     if (fractional_step == 0)
  758.       {
  759.         /*
  760.           No fractional displacement-- just copy the pixels.
  761.         */
  762.         switch (direction)
  763.         {
  764.           case UP:
  765.           {
  766.             /*
  767.               Transfer pixels top-to-bottom.
  768.             */
  769.             p=image->pixels+image->columns*y_offset+x_offset;
  770.             q=p-step*image->columns;
  771.             for (i=0; i < height; i++)
  772.             {
  773.               *q=(*p);
  774.               q+=image->columns;
  775.               p+=image->columns;
  776.             }
  777.             /*
  778.               Set old column to background color.
  779.             */
  780.             for (i=0; i < step; i++)
  781.             {
  782.               q->red=background.red;
  783.               q->green=background.green;
  784.               q->blue=background.blue;
  785.               q->index=background.index;
  786.               q+=image->columns;
  787.             }
  788.             break;
  789.           }
  790.           case DOWN:
  791.           {
  792.             /*
  793.               Transfer pixels bottom-to-top.
  794.             */
  795.             p=image->pixels+image->columns*(y_offset+height)+x_offset;
  796.             q=p+step*image->columns;
  797.             for (i=0; i < height; i++)
  798.             {
  799.               q-=image->columns;
  800.               p-=image->columns;
  801.               *q=(*p);
  802.             }
  803.             /*
  804.               Set old column to background color.
  805.             */
  806.             for (i=0; i < step; i++)
  807.             {
  808.               q-=image->columns;
  809.               q->red=background.red;
  810.               q->green=background.green;
  811.               q->blue=background.blue;
  812.               q->index=background.index;
  813.             }
  814.             break;
  815.           }
  816.         }
  817.         continue;
  818.       }
  819.     /*
  820.       Fractional displacment.
  821.     */
  822.     step++;
  823.     last_pixel.red=background.red;
  824.     last_pixel.green=background.green;
  825.     last_pixel.blue=background.blue;
  826.     last_pixel.index=background.index;
  827.     switch (direction)
  828.     {
  829.       case UP:
  830.       {
  831.         /*
  832.           Transfer pixels top-to-bottom.
  833.         */
  834.         p=image->pixels+image->columns*y_offset+x_offset;
  835.         q=p-step*image->columns;
  836.         for (i=0; i < height; i++)
  837.         {
  838.           red=DownShift(last_pixel.red*(UpShift(1)-fractional_step)+p->red*
  839.             fractional_step);
  840.           green=DownShift(last_pixel.green*(UpShift(1)-fractional_step)+
  841.             p->green*fractional_step);
  842.           blue=DownShift(last_pixel.blue*(UpShift(1)-fractional_step)+p->blue*
  843.             fractional_step);
  844.           index=DownShift(last_pixel.index*(UpShift(1)-fractional_step)+
  845.             p->index*fractional_step);
  846.           last_pixel=(*p);
  847.           p+=image->columns;
  848.           q->red=range_limit[red];
  849.           q->green=range_limit[green];
  850.           q->blue=range_limit[blue];
  851.           if (index < 0)
  852.             q->index=0;
  853.           else
  854.             if (index > MaxColormapSize)
  855.               q->index=MaxColormapSize;
  856.             else
  857.               q->index=(unsigned short) index;
  858.           q+=image->columns;
  859.         }
  860.         /*
  861.           Set old column to background color.
  862.         */
  863.         red=DownShift(last_pixel.red*(UpShift(1)-fractional_step)+
  864.           background.red*fractional_step);
  865.         green=DownShift(last_pixel.green*(UpShift(1)-fractional_step)+
  866.           background.green*fractional_step);
  867.         blue=DownShift(last_pixel.blue*(UpShift(1)-fractional_step)+
  868.           background.blue*fractional_step);
  869.         index=DownShift(last_pixel.index*(UpShift(1)-fractional_step)+
  870.           background.index*fractional_step);
  871.         q->red=range_limit[red];
  872.         q->green=range_limit[green];
  873.         q->blue=range_limit[blue];
  874.         if (index < 0)
  875.           q->index=0;
  876.         else
  877.           if (index > MaxColormapSize)
  878.             q->index=MaxColormapSize;
  879.           else
  880.             q->index=(unsigned short) index;
  881.         q+=image->columns;
  882.         for (i=0; i < step-1; i++)
  883.         {
  884.           q->red=background.red;
  885.           q->green=background.green;
  886.           q->blue=background.blue;
  887.           q->index=background.index;
  888.           q+=image->columns;
  889.         }
  890.         break;
  891.       }
  892.       case DOWN:
  893.       {
  894.         /*
  895.           Transfer pixels bottom-to-top.
  896.         */
  897.         p=image->pixels+image->columns*(y_offset+height)+x_offset;
  898.         q=p+step*image->columns;
  899.         for (i=0; i < height; i++)
  900.         {
  901.           p-=image->columns;
  902.           red=DownShift(last_pixel.red*(UpShift(1)-fractional_step)+p->red*
  903.             fractional_step);
  904.           green=DownShift(last_pixel.green*(UpShift(1)-fractional_step)+
  905.             p->green*fractional_step);
  906.           blue=DownShift(last_pixel.blue*(UpShift(1)-fractional_step)+p->blue*
  907.             fractional_step);
  908.           index=DownShift(last_pixel.index*(UpShift(1)-fractional_step)+
  909.             p->index*fractional_step);
  910.           last_pixel=(*p);
  911.           q-=image->columns;
  912.           q->red=range_limit[red];
  913.           q->green=range_limit[green];
  914.           q->blue=range_limit[blue];
  915.           if (index < 0)
  916.             q->index=0;
  917.           else
  918.             if (index > MaxColormapSize)
  919.               q->index=MaxColormapSize;
  920.             else
  921.               q->index=(unsigned short) index;
  922.         }
  923.         /*
  924.           Set old column to background color.
  925.         */
  926.         red=DownShift(last_pixel.red*(UpShift(1)-fractional_step)+
  927.           background.red*fractional_step);
  928.         green=DownShift(last_pixel.green*(UpShift(1)-fractional_step)+
  929.           background.green*fractional_step);
  930.         blue=DownShift(last_pixel.blue*(UpShift(1)-fractional_step)+
  931.           background.blue*fractional_step);
  932.         index=DownShift(last_pixel.index*(UpShift(1)-fractional_step)+
  933.           background.index*fractional_step);
  934.         q-=image->columns;
  935.         q->red=range_limit[red];
  936.         q->green=range_limit[green];
  937.         q->blue=range_limit[blue];
  938.         if (index < 0)
  939.           q->index=0;
  940.         else
  941.           if (index > MaxColormapSize)
  942.             q->index=MaxColormapSize;
  943.           else
  944.             q->index=(unsigned short) index;
  945.         for (i=0; i < step-1; i++)
  946.         {
  947.           q-=image->columns;
  948.           q->red=background.red;
  949.           q->green=background.green;
  950.           q->blue=background.blue;
  951.           q->index=background.index;
  952.         }
  953.         break;
  954.       }
  955.     }
  956.   }
  957. }
  958.  
  959. /*
  960. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  961. %                                                                             %
  962. %                                                                             %
  963. %                                                                             %
  964. %   R o t a t e I m a g e                                                     %
  965. %                                                                             %
  966. %                                                                             %
  967. %                                                                             %
  968. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  969. %
  970. %  Function RotateImage creates a new image that is a rotated copy of an
  971. %  existing one.  Positive angles rotate counter-clockwise (right-hand rule),
  972. %  while negative angles rotate clockwise.  Rotated images are usually larger
  973. %  than the originals and have 'empty' triangular corners.  X axis.  Empty
  974. %  triangles left over from shearing the image are filled with the color
  975. %  defined by the pixel at location (0,0).  RotateImage allocates the memory
  976. %  necessary for the new Image structure and returns a pointer to the new
  977. %  image.
  978. %
  979. %  Function RotateImage is based on the paper "A Fast Algorithm for General
  980. %  Raster Rotatation" by Alan W. Paeth.  RotateImage is adapted from a similiar
  981. %  routine based on the Paeth paper written by Michael Halle of the Spatial
  982. %  Imaging Group, MIT Media Lab.
  983. %
  984. %  The format of the RotateImage routine is:
  985. %
  986. %      RotateImage(image,degrees,clip)
  987. %
  988. %  A description of each parameter follows.
  989. %
  990. %    o status: Function RotateImage returns a pointer to the image after
  991. %      rotating.  A null image is returned if there is a memory shortage.
  992. %
  993. %    o image: The address of a structure of type Image;  returned from
  994. %      ReadImage.
  995. %
  996. %    o degrees: Specifies the number of degrees to rotate the image.
  997. %
  998. %    o clip: A value other than zero clips the corners of the rotated
  999. %      image and retains the original image size.
  1000. %
  1001. %
  1002. */
  1003. Image *RotateImage(image,degrees,clip)
  1004. Image
  1005.   *image;
  1006.  
  1007. double
  1008.   degrees;
  1009.  
  1010. unsigned int
  1011.   clip;
  1012. {
  1013.   ColorPacket
  1014.     background;
  1015.  
  1016.   double
  1017.     x_shear,
  1018.     y_shear;
  1019.  
  1020.   Image
  1021.     *clipped_image,
  1022.     *integral_image,
  1023.     *rotated_image;
  1024.  
  1025.   int
  1026.     x_offset,
  1027.     y_offset;
  1028.  
  1029.   RectangleInfo
  1030.     border_info;
  1031.  
  1032.   register int
  1033.     i;
  1034.  
  1035.   unsigned char
  1036.     *range_limit,
  1037.     *range_table;
  1038.  
  1039.   unsigned int
  1040.     height,
  1041.     rotations,
  1042.     width,
  1043.     y_width;
  1044.  
  1045.   /*
  1046.     Adjust rotation angle.
  1047.   */
  1048.   while (degrees < -45.0)
  1049.     degrees+=360.0;
  1050.   for (rotations=0; degrees > 45.0; rotations++)
  1051.     degrees-=90.0;
  1052.   rotations%=4;
  1053.   /*
  1054.     Calculate shear equations.
  1055.   */
  1056.   x_shear=(-tan(DegreesToRadians(degrees)/2.0));
  1057.   y_shear=sin(DegreesToRadians(degrees));
  1058.   integral_image=IntegralRotateImage(image,rotations);
  1059.   if ((x_shear == 0.0) || (y_shear == 0.0))
  1060.     return(integral_image);
  1061.   /*
  1062.     Initialize range table.
  1063.   */
  1064.   range_table=(unsigned char *) malloc(3*(MaxRGB+1)*sizeof(unsigned char));
  1065.   if (range_table == (unsigned char *) NULL)
  1066.     {
  1067.       DestroyImage(integral_image);
  1068.       Warning("Unable to rotate image","Memory allocation failed");
  1069.       return((Image *) NULL);
  1070.     }
  1071.   for (i=0; i <= MaxRGB; i++)
  1072.   {
  1073.     range_table[i]=0;
  1074.     range_table[i+(MaxRGB+1)]=(unsigned char) i;
  1075.     range_table[i+(MaxRGB+1)*2]=MaxRGB;
  1076.   }
  1077.   range_limit=range_table+(MaxRGB+1);
  1078.   /*
  1079.     Compute image size.
  1080.   */
  1081.   width=image->columns;
  1082.   height=image->rows;
  1083.   if ((rotations == 1) || (rotations == 3))
  1084.     {
  1085.       width=image->rows;
  1086.       height=image->columns;
  1087.     }
  1088.   y_width=width+(int) ceil(fabs(x_shear)*(double) (height-1));
  1089.   x_offset=(width+
  1090.     ((int) ceil(fabs(x_shear)*(double) (height-1)) << 1)-width) >> 1;
  1091.   y_offset=(height+(int) ceil(fabs(y_shear)*(double) (y_width-1))-height) >> 1;
  1092.   /*
  1093.     Surround image with border of background color.
  1094.   */
  1095.   background.red=image->pixels[0].red;
  1096.   background.green=image->pixels[0].green;
  1097.   background.blue=image->pixels[0].blue;
  1098.   background.index=image->pixels[0].index;
  1099.   border_info.width=integral_image->columns+(x_offset << 1);
  1100.   border_info.height=integral_image->rows+((y_offset+1) << 1);
  1101.   border_info.x=x_offset;
  1102.   border_info.y=y_offset+1;
  1103.   rotated_image=BorderImage(integral_image,&border_info,&background,
  1104.     &background);
  1105.   DestroyImage(integral_image);
  1106.   if (rotated_image == (Image *) NULL)
  1107.     {
  1108.       Warning("Unable to rotate image","Memory allocation failed");
  1109.       return((Image *) NULL);
  1110.     }
  1111.   rotated_image->class=DirectClass;
  1112.   /*
  1113.     Perform a fractional rotation.  First, shear the image rows.
  1114.   */
  1115.   XShearImage(rotated_image,x_shear,width,height,x_offset,
  1116.     ((int) (rotated_image->rows-height-2) >> 1)+1,background,range_limit);
  1117.   /*
  1118.     Shear the image columns.
  1119.   */
  1120.   YShearImage(rotated_image,y_shear,y_width,height,
  1121.     ((int) (rotated_image->columns-y_width) >> 1),y_offset+1,background,
  1122.     range_limit);
  1123.   /*
  1124.     Shear the image rows again.
  1125.   */
  1126.   XShearImage(rotated_image,x_shear,y_width,rotated_image->rows-2,
  1127.     ((int) (rotated_image->columns-y_width) >> 1),1,background,range_limit);
  1128.   (void) free((char *) range_table);
  1129.   clipped_image=ClipShearImage(rotated_image,x_shear,y_shear,width,height,clip);
  1130.   DestroyImage(rotated_image);
  1131.   return(clipped_image);
  1132. }
  1133.  
  1134. /*
  1135. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1136. %                                                                             %
  1137. %                                                                             %
  1138. %                                                                             %
  1139. %   S h e a r I m a g e                                                       %
  1140. %                                                                             %
  1141. %                                                                             %
  1142. %                                                                             %
  1143. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1144. %
  1145. %  Function ShearImage creates a new image that is a sheared copy of an
  1146. %  existing one.  Shearing slides one edge of an image along the X or Y
  1147. %  axis, creating a parallelogram.  An X direction shear slides an edge
  1148. %  along the X axis, while a Y direction shear slides an edge along the Y
  1149. %  axis.  The amount of the shear is controlled by a shear angle.  For X
  1150. %  direction shears, x_shear is measured relative to the Y axis, and
  1151. %  similarly, for Y direction shears y_shear is measured relative to the
  1152. %  X axis.  Empty triangles left over from shearing the image are filled
  1153. %  with the color defined by the pixel at location (0,0).  ShearImage
  1154. %  allocates the memory necessary for the new Image structure and returns
  1155. %  a pointer to the new image.
  1156. %
  1157. %  Function ShearImage is based on the paper "A Fast Algorithm for General
  1158. %  Raster Rotatation" by Alan W. Paeth.
  1159. %
  1160. %  The format of the ShearImage routine is:
  1161. %
  1162. %      ShearImage(image,x_shear,y_shear,clip)
  1163. %
  1164. %  A description of each parameter follows.
  1165. %
  1166. %    o status: Function ShearImage returns a pointer to the image after
  1167. %      rotating.  A null image is returned if there is a memory shortage.
  1168. %
  1169. %    o image: The address of a structure of type Image;  returned from
  1170. %      ReadImage.
  1171. %
  1172. %    o x_shear, y_shear: Specifies the number of degrees to shear the image.
  1173. %
  1174. %    o clip: A value other than zero clips the corners of the rotated
  1175. %      image and retains the original image size.
  1176. %
  1177. %
  1178. */
  1179. Image *ShearImage(image,x_shear,y_shear,clip)
  1180. Image
  1181.   *image;
  1182.  
  1183. double
  1184.   x_shear,
  1185.   y_shear;
  1186.  
  1187. unsigned int
  1188.   clip;
  1189. {
  1190.   ColorPacket
  1191.     background;
  1192.  
  1193.   Image
  1194.     *clipped_image,
  1195.     *sheared_image;
  1196.  
  1197.   int
  1198.     x_offset,
  1199.     y_offset;
  1200.  
  1201.   RectangleInfo
  1202.     border_info;
  1203.  
  1204.   register int
  1205.     i;
  1206.  
  1207.   unsigned char
  1208.     *range_limit,
  1209.     *range_table;
  1210.  
  1211.   unsigned int
  1212.     y_width;
  1213.  
  1214.   /*
  1215.     Adjust shear angle.
  1216.   */
  1217.   while (x_shear < -45.0)
  1218.     x_shear+=360.0;
  1219.   while (x_shear > 45.0)
  1220.     x_shear-=90.0;
  1221.   while (y_shear < -45.0)
  1222.     y_shear+=360.0;
  1223.   while (y_shear > 45.0)
  1224.     y_shear-=90.0;
  1225.   x_shear=(-tan(DegreesToRadians(x_shear)/2.0));
  1226.   y_shear=sin(DegreesToRadians(y_shear));
  1227.   /*
  1228.     Initialize range table.
  1229.   */
  1230.   range_table=(unsigned char *) malloc(3*(MaxRGB+1)*sizeof(unsigned char));
  1231.   if (range_table == (unsigned char *) NULL)
  1232.     {
  1233.       Warning("Unable to shear image","Memory allocation failed");
  1234.       return((Image *) NULL);
  1235.     }
  1236.   for (i=0; i <= MaxRGB; i++)
  1237.   {
  1238.     range_table[i]=0;
  1239.     range_table[i+(MaxRGB+1)]=(unsigned char) i;
  1240.     range_table[i+(MaxRGB+1)*2]=MaxRGB;
  1241.   }
  1242.   range_limit=range_table+(MaxRGB+1);
  1243.   /*
  1244.     Compute image size.
  1245.   */
  1246.   y_width=image->columns+(int) ceil(fabs(x_shear)*(double) (image->rows-1));
  1247.   x_offset=(image->columns+((int) ceil(fabs(x_shear)*(double)
  1248.     (image->rows-1)) << 1)-image->columns) >> 1;
  1249.   y_offset=(image->rows+(int) ceil(fabs(y_shear)*(double) (y_width-1))-
  1250.     image->rows) >> 1;
  1251.   /*
  1252.     Surround image with border of background color.
  1253.   */
  1254.   background.red=image->pixels[0].red;
  1255.   background.green=image->pixels[0].green;
  1256.   background.blue=image->pixels[0].blue;
  1257.   background.index=image->pixels[0].index;
  1258.   border_info.width=image->columns+(x_offset << 1);
  1259.   border_info.height=image->rows+((y_offset+1) << 1);
  1260.   border_info.x=x_offset;
  1261.   border_info.y=y_offset+1;
  1262.   sheared_image=BorderImage(image,&border_info,&background,&background);
  1263.   if (sheared_image == (Image *) NULL)
  1264.     {
  1265.       Warning("Unable to shear image","Memory allocation failed");
  1266.       return((Image *) NULL);
  1267.     }
  1268.   sheared_image->class=DirectClass;
  1269.   /*
  1270.     Shear the image rows.
  1271.   */
  1272.   if (x_shear != 0.0)
  1273.     XShearImage(sheared_image,x_shear,image->columns,image->rows,x_offset,
  1274.       ((int) (sheared_image->rows-image->rows) >> 1)+1,background,range_limit);
  1275.   /*
  1276.     Shear the image columns.
  1277.   */
  1278.   if (y_shear != 0.0)
  1279.     YShearImage(sheared_image,y_shear,y_width,image->rows,(int)
  1280.       ((sheared_image->columns-y_width) >> 1),y_offset+1,background,
  1281.       range_limit);
  1282.   (void) free((char *) range_table);
  1283.   clipped_image=ClipShearImage(sheared_image,x_shear,y_shear,image->columns,
  1284.     image->rows,clip);
  1285.   DestroyImage(sheared_image);
  1286.   return(clipped_image);
  1287. }
  1288.